# -*- coding: utf-8 -*-
from accost import SESSION_USER_KEY
from storm.locals import *
from datetime import datetime
import threading


def get_hexdigest(algorithm, salt, raw_password):
    """
    Returns a string of the hexdigest of the given plaintext password and salt
    using the given algorithm ('md5', 'sha1' or 'crypt').
    """
    raw_password, salt = str(raw_password), str(salt)
    if algorithm == 'crypt':
        try:
            import crypt
        except ImportError:
            raise ValueError('"crypt" password algorithm not supported in this environment')
        return crypt.crypt(raw_password, salt)
    # The rest of the supported algorithms are supported by hashlib, but
    # hashlib is only available in Python 2.5.
    try:
        import hashlib
    except ImportError:
        if algorithm == 'md5':
            import md5
            return md5.new(salt + raw_password).hexdigest()
        elif algorithm == 'sha1':
            import sha
            return sha.new(salt + raw_password).hexdigest()
    else:
        if algorithm == 'md5':
            return hashlib.md5(salt + raw_password).hexdigest()
        elif algorithm == 'sha1':
            return hashlib.sha1(salt + raw_password).hexdigest()
    raise ValueError("Got unknown password algorithm type in password.")


def check_password(raw_password, enc_password):
    """
    Returns a boolean of whether the raw_password was correct. Handles
    encryption formats behind the scenes.
    """
    algo, salt, hsh = enc_password.split('$')
    return hsh == get_hexdigest(algo, salt, raw_password)


class User(Storm):
    __storm_table__ = "auth_user"
    id = Int(primary=True)
    username = Unicode()
    password = Unicode()
    last_login = DateTime(default_factory=datetime.now)
    date_joined = DateTime(default_factory=datetime.now)
    role_id = Int()
    role = Reference(role_id, "Role.id")
    root = Unicode()

    @classmethod
    def from_id(cls, id):
        return store.get(cls, id)

    @classmethod
    def new(cls, username, password):
        try:
            role = store.get(Role, Role.name==u"new")
        except:
            role = Role()
            role.name = u'new'
        user = cls()
        user.role = role
        user.username = username
        user.setPassword(password)
        store.add(user)
        store.commit()
        return user

    def login(self, request):
        request.user = self
        self.last_login = datetime.now()
        store.add(self)
        store.commit()
        request.session[SESSION_USER_KEY] = self.id

    def setPassword(self, raw_password):
        import random
        algo = 'sha1'
        salt = get_hexdigest(algo, str(random.random()),
                str(random.random()))[:5]
        hsh = get_hexdigest(algo, salt, raw_password)
        self.password = u'%s$%s$%s' % (algo, salt, hsh)

    def checkPassword(self, raw_password):
        """
        Returns a boolean of whether the raw_password was correct. Handles
        encryption formats behind the scenes.
        """
        # Backwards-compatibility check. Older passwords won't include the
        # algorithm or salt.
        if '$' not in self.password:
            is_correct = (self.password == get_hexdigest('md5', '', raw_password))
            if is_correct:
                # Convert the password to the new, more secure format.
                self.setPassword(raw_password)
                store.add(self)
                store.commit()
            return is_correct
        return check_password(raw_password, self.password)

    def hasPermission(self, permission):
        return bool(store.find(RolePermission,
            RolePermission.role_id == self.role_id,
            RolePermission.permission_id == permission.id
        ).count())


class Role(Storm):
    __storm_table__ = "auth_role"
    id = Int(primary=True)
    name = Unicode()
    users = ReferenceSet(id, User.role_id)

    def hasPermission(self, permission):
        return bool(store.find(RolePermission,
                RolePermission.role_id==self.id,
                RolePermission.permission_id==permission.id
        ).count())


class Perm(Storm):
    __storm_table__ = "auth_permission"
    id = Int(primary=True)
    name = Unicode()
    description = Unicode()


class Permission(object):
    id = 0
    all = []
    def __init__(self, name):
        Permission.id += 1
        self.id = Permission.id
        self.name = name
        Permission.all.append(self)

add_user = Permission(u'添加用户')
add_role = Permission(u'添加组')
delete_role = Permission(u'删除组')
update_permission = Permission(u'更改权限')
update_role = Permission(u'更改组名')
add_source = Permission(u'添加网络视频源')
add_playlist = Permission(u'添加播放列表')
add_stream = Permission(u'发布流')


class RolePermission(Storm):
    __storm_table__ = "auth_role_permission"
    id = Int(primary=True)
    role_id = Int()
    role = Reference(role_id, Role.id)
    permission_id = Int()
    #permission = Reference(permission_id, Permission.id)


def logout(request):
    try:
        del request.session[SESSION_USER_KEY]
    except KeyError:
        pass
    request.user = None
